package com.wxzhou.wangzhuan.security;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.wxzhou.wangzhuan.config.ApiSecurityConfig;
import com.wxzhou.wangzhuan.dto.ResponseDto;
import com.wxzhou.wangzhuan.util.ApiSecurityUtils;
import jakarta.inject.Inject;
import jakarta.ws.rs.container.ContainerRequestContext;
import jakarta.ws.rs.container.ContainerRequestFilter;
import jakarta.ws.rs.container.ContainerResponseContext;
import jakarta.ws.rs.container.ContainerResponseFilter;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.ext.Provider;
import org.jboss.logging.Logger;

import java.io.IOException;
import java.nio.charset.StandardCharsets;

@Provider
public class ApiSecurityInterceptor implements ContainerRequestFilter, ContainerResponseFilter {

    private static final Logger LOG = Logger.getLogger(ApiSecurityInterceptor.class);

    @Inject
    ApiSecurityConfig securityConfig;

    @Inject
    ObjectMapper objectMapper;

    @Inject
    UserContext userContext;


    @Override
    public void filter(ContainerRequestContext requestContext) throws IOException {
        if (!securityConfig.isEnabled()) {
            return;
        }

//        Optional<UserInfoDto> userInfoOpt = userContext.getCurrentUserInfo();


        try {
            // 只处理API请求 - 使用更严谨的路径检查
            String path = requestContext.getUriInfo().getPath();
            String requestUri = requestContext.getUriInfo().getRequestUri().getPath();
            String method = requestContext.getMethod(); //GET,通常用于网页请求

            //判断是否为网页请求

            // 检查路径是否包含API标识
            boolean isApiRequest = isApiPath(path, requestUri);

            if (!isApiRequest) {
                LOG.debug("Skipping non-API request path=" + path + "requestUri=" + requestUri);
                return;
            }

            LOG.debug("Processing API request path=" + path + " requestUri=" + requestUri);

            // 在ReaderInterceptor中处理读取/解密/校验，这里把原始路径和查询参数透传给它
            if (isApiRequest && ("POST".equals(method) || "DELETE".equals(method) || "PUT".equals(method))) {
                requestContext.getHeaders().putSingle("x-original-path", path);
            }


            // 透传查询参数，特别是key参数
//            String queryString = requestContext.getUriInfo().getRequestUri().getQuery();
//            if (queryString != null && !queryString.isEmpty()) {//                // 解析查询参数，找到key值
//                String[] params = queryString.split("&");
//                for (String param : params) {
//                    if (param.startsWith("key=")) {
//                        String keyValue = param.substring(4); // 去掉"key="前缀
//                        requestContext.getHeaders().putSingle("x-query-key", keyValue);
//                        LOG.debug("Found key parameter in query string: " + keyValue);
//                        break;
//                    }
//                }
//            }

        } catch (Exception e) {
            LOG.error("Security validation failed error=" + e.getMessage());
            abortRequest(requestContext, "Security validation failed: " + e.getMessage());
        }
    }

    /**
     * 中止请求
     */
    private void abortRequest(ContainerRequestContext requestContext, String message) {
        // 使用ResponseDto结构，保持一致性
        ResponseDto<Void> errorResponse = ResponseDto.fail(message, 406);

        requestContext.abortWith(Response.status(Response.Status.BAD_REQUEST)
                .entity(errorResponse)
                .type(MediaType.APPLICATION_JSON)
                .build());
    }

    @Override
    public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext) throws IOException {
        if (!securityConfig.isEnabled()) {
            return;
        }

        try {
            // 获取存储的动态密钥、盐值和请求时间戳（由ReaderInterceptor设置到RequestScoped上下文）
            String dynamicKey = null;
            String salt = null;
            Long requestCtime = null;
            try {
                jakarta.enterprise.inject.spi.CDI<Object> current = jakarta.enterprise.inject.spi.CDI.current();
                ApiSecurityRequestContext ctx = current.select(ApiSecurityRequestContext.class).get();
                dynamicKey = ctx.getDynamicKey();
                salt = ctx.getSalt();
                requestCtime = ctx.getRequestCtime();
            } catch (Exception ignored) {
            }

            if (dynamicKey == null || salt == null || requestCtime == null) {
                return;
            }

            // 获取原始响应数据
            Object responseEntity = responseContext.getEntity();
            if (responseEntity == null) {
                return;
            }

            // 检查是否为ResponseDto类型
            if (responseEntity instanceof ResponseDto) {
                ResponseDto<?> originalResponse = (ResponseDto<?>) responseEntity;

                // 将原始响应对象转换为JSON字符串
                String responseJson = convertToJson(originalResponse);
                LOG.infof("解密响应原文: %s", responseJson);
                // 加密响应数据
                String encryptedResponse = ApiSecurityUtils.encrypt(responseJson, dynamicKey);

                // 创建新的ResponseDto，保持原有结构，将加密数据放入data字段
                ResponseDto<Object> encryptedResponseDto = new ResponseDto<>(
                        encryptedResponse, originalResponse.getMsg(), originalResponse.getCode()
                );

                // 设置加密响应，保持原有结构
                responseContext.setEntity(encryptedResponseDto);
                responseContext.setStatus(originalResponse.getCode());

                LOG.info("Response encrypted successfully while maintaining ResponseDto structure");

            } else {
                // 如果不是ResponseDto，按原逻辑处理
                String responseJson = convertToJson(responseEntity);
                LOG.infof("解密响应原文: %s", responseJson);
                String encryptedResponse = ApiSecurityUtils.encrypt(responseJson, dynamicKey);


                ResponseDto<Object> encryptedResponseDto = new ResponseDto<>(
                        encryptedResponse, "Success", 200
                );

                responseContext.setEntity(encryptedResponseDto);
                responseContext.setStatus(200);

                LOG.info("Non-ResponseDto response encrypted successfully");
            }

        } catch (Exception e) {
            LOG.error("Failed to encrypt response error=" + e.getMessage());
            // 如果加密失败，返回原始响应
        }
    }

    private String convertToJson(Object obj) {
        try {
            return objectMapper.writeValueAsString(obj);
        } catch (Exception e) {
            LOG.error("Failed to convert response to JSON error=" + e.getMessage());
            return obj.toString();
        }
    }

    /**
     * 检查请求路径是否为API请求
     * 支持多种路径格式：
     * 1. 直接路径: /api/user/collects
     * 2. 带上下文前缀: /myapp/api/user/collects
     * 3. 相对路径: api/user/collects
     * 4. 带版本号: /api/v1/user/collects
     * <p>
     * 注意：测试接口 /api/test/security/* 会被排除，避免循环依赖
     *
     * @param path       相对路径
     * @param requestUri 完整请求URI
     * @return 是否为API请求
     */
    private boolean isApiPath(String path, String requestUri) {
        if (path == null && requestUri == null) {
            return false;
        }

        // 排除测试接口，避免循环依赖
        if (isExcluedPath(path) || isExcluedPath(requestUri)) {
            LOG.debug("Skipping test path path=" + path + "requestUri=" + requestUri);
            return false;
        }

        // 检查相对路径
        if (path != null) {
            // 移除开头的斜杠，统一格式
            String normalizedPath = path.startsWith("/") ? path.substring(1) : path;

            // 检查是否以api开头
            if (normalizedPath.startsWith("api/")) {
                return true;
            }

            // 检查是否包含/api/（支持版本号等）
            if (normalizedPath.contains("/api/")) {
                return true;
            }
        }

        // 检查完整请求URI
        if (requestUri != null) {
            // 移除开头的斜杠，统一格式
            String normalizedUri = requestUri.startsWith("/") ? requestUri.substring(1) : requestUri;

            // 检查是否以api开头
            if (normalizedUri.startsWith("api/")) {
                return true;
            }

            // 检查是否包含/api/（支持上下文前缀和版本号）
            if (normalizedUri.contains("/api/")) {
                return true;
            }
        }

        return false;
    }

    /**
     * 检查是否为忽略路径1
     * 测试路径不进行加密处理，避免循环依赖
     */
    private boolean isExcluedPath(String path) {
//        return true;
        if (path == null) {
            return false;
        }

        // 移除开头的斜杠，统一格式
        String normalizedPath = path.startsWith("/") ? path.substring(1) : path;

        // 排除缓存管理路径，由 AdminApiSecurityRequestFilter 处理
        // 排除评论接口，开发阶段不进行加密处理
        return normalizedPath.startsWith("api/cache-management") || normalizedPath.startsWith("admin/") || normalizedPath.startsWith("api/yuedu/callback");
    }
} 